//********************************************************************
//	created:	16:10:2011   19:18
//	filename: 	requestmanager.h
//	author:		tiamo
//	purpose:	async request manager
//********************************************************************

#pragma once

namespace utils
{
	//
	// request
	//
	class BaseRequest : public RefCountedObject
	{
	public:
		//
		// callback
		//
		typedef std::function<void(BaseRequest*)>							Callback;

	public:
		//
		// constructor
		//
		BaseRequest(wchar_t const* requestName)								{mResult = -1; mMaxRetry = 3; mUserData = nullptr; mRequestName = requestName;}

		//
		// destructor
		//
		virtual ~BaseRequest()												{}

		//
		// do
		//
		void doRequest();

		//
		// done
		//
		void requestDone();

		//
		// set callback
		//
		void setCallback(Callback&& callback)								{mCallback = std::move(callback);}

		//
		// set callback
		//
		void setCallback(Callback const& callback)							{mCallback = callback;}

		//
		// get callback
		//
		Callback const& getCallback() const									{return mCallback;}

		//
		// reset callback
		//
		void resetCallback()												{mCallback = nullptr;}

		//
		// set retry count
		//
		void setMaxRetry(uint32_t maxRetry)									{mMaxRetry = maxRetry;}

		//
		// get result
		//
		int32_t getResult() const											{return mResult;}

		//
		// set result
		//
		void setResult(int32_t result)										{mResult = result;}

		//
		// set user data
		//
		void setUserData(void* userData)									{mUserData = userData;}

		//
		// get user data
		//
		void* getUserData() const											{return mUserData;}

	protected:
		//
		// do request imp
		//
		virtual void doRequestImp()											{}

	protected:
		//
		// result
		//
		int32_t																mResult;

		//
		// retry
		//
		uint32_t															mMaxRetry;

		//
		// callback
		//
		Callback															mCallback;

		//
		// user data
		//
		void*																mUserData;

		//
		// request name
		//
		wchar_t const*														mRequestName;
	};

	//
	// request manager
	//
	class RequestManager : public utils::Thread
	{
	public:
		//
		// constructor
		//
		RequestManager(utils::Event& stopEvent) : mStopEvent(stopEvent)		{}

		//
		// destructor
		//
		virtual ~RequestManager()											{}
		
		//
		// process finished request
		//
		void processFinishedRequest();

		//
		// insert pending request
		//
		void pushPendingRequest(SmartPointer<BaseRequest> const& r)			{mPendingQueue.push(r);}

	protected:
		//
		// process pending request
		//
		void processPendingRequest();

		//
		// run
		//
		virtual void run()													{while(!mStopEvent.wait(100)) processPendingRequest(); processPendingRequest();}

		//
		// pop pending request
		//
		SmartPointer<BaseRequest> popPendingRequest()						{return mPendingQueue.pop();}

		//
		// push finished request
		//
		void pushFinishedRequest(SmartPointer<BaseRequest> const& r)		{mFinishedQueue.push(r);}

		//
		// pop finished request
		//
		SmartPointer<BaseRequest> popFinishedRequest()						{return mFinishedQueue.pop();}

	private:
		//
		// pending queue
		//
		LockedQueue<SmartPointer<BaseRequest>>								mPendingQueue;

		//
		// finished queue
		//
		LockedQueue<SmartPointer<BaseRequest>>								mFinishedQueue;

		//
		// stop event
		//
		utils::Event&														mStopEvent;
	};
}
